﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;

namespace Tiscs.Practices.Web.Services.Client
{
    /// <summary>
    /// 操作信息类。
    /// </summary>
    public abstract class OperationBase : INotifyPropertyChanged
    {
        /// <summary>
        /// 构造方法。
        /// </summary>
        /// <param name="userState">用户状态。</param>
        public OperationBase(object userState)
        {
            UserState = userState;
        }

        #region Properties

        #region CanCancel, SupportsCancellation

        /// <summary>
        /// 是否支持取消操作。
        /// </summary>
        protected virtual bool SupportsCancellation
        {
            get
            {
                return false;
            }
        }

        /// <summary>
        /// 该操作是否可以取消。
        /// </summary>
        public bool CanCancel
        {
            get
            {
                return this.SupportsCancellation && !IsComplete;
            }
        }

        #endregion

        #region Error

        private Exception _error;

        /// <summary>
        /// 操作执行异常。
        /// </summary>
        public Exception Error
        {
            get
            {
                return _error;
            }
            set
            {
                _error = value;
                RaisePropertyChanged("Error");
                RaisePropertyChanged("HasError");
            }
        }

        #endregion

        #region HasError

        /// <summary>
        /// 操作是否包含异常。
        /// </summary>
        public bool HasError
        {
            get
            {
                return Error != null;
            }
        }

        #endregion

        #region IsComplete

        private bool _isComplete = false;

        /// <summary>
        /// 操作是否已经完成。
        /// </summary>
        public bool IsComplete
        {
            get
            {
                return _isComplete;
            }
            private set
            {
                _isComplete = value;
                RaisePropertyChanged("IsComplete");
            }
        }

        #endregion

        #region IsCanceled

        private bool _isCanceled;

        /// <summary>
        /// 操作是否已经取消。
        /// </summary>
        public bool IsCanceled
        {
            get
            {
                return _isCanceled;
            }
            private set
            {
                _isCanceled = value;
                RaisePropertyChanged("IsCanceled");
            }
        }

        #endregion

        #region IsErrorHandled

        private bool _isErrorHandled;

        /// <summary>
        /// 操作异常是否已经被处理。
        /// </summary>
        public bool IsErrorHandled
        {
            get
            {
                return _isErrorHandled;
            }
            private set
            {
                _isErrorHandled = value;
                RaisePropertyChanged("IsErrorHandled");
            }
        }

        #endregion

        #region UserState

        private object _userState;

        /// <summary>
        /// 用户状态。
        /// </summary>
        public object UserState
        {
            get
            {
                return _userState;
            }
            private set
            {
                _userState = value;
                RaisePropertyChanged("UserState");
            }
        }

        #endregion

        #region Result

        private object _result = null;

        /// <summary>
        /// 操作结果。
        /// </summary>
        protected object Result
        {
            get
            {
                return _result;
            }
            private set
            {
                _result = value;
                RaisePropertyChanged("Result");
            }
        }

        #endregion

        #endregion

        #region Methods

        /// <summary>
        /// 确定操作尚未完成。如果操作尚未完成，则抛出异常。
        /// </summary>
        private void EnsureNotCompleted()
        {
            if (IsComplete)
            {
                throw new InvalidOperationException();
            }
        }

        /// <summary>
        /// 将操作异常标记为已处理。
        /// </summary>
        public void MarkErrorAsHandled()
        {
            if (!HasError)
            {
                throw new InvalidOperationException();
            }
            IsErrorHandled = true;
        }

        /// <summary>
        /// 结束操作。
        /// </summary>
        /// <param name="error">操作异常。</param>
        protected void Complete(Exception error)
        {
            if (error == null)
            {
                throw new ArgumentNullException("error");
            }
            else
            {
                EnsureNotCompleted();
                Error = error;
                IsComplete = true;
                InvokeCompleteAction();
                RaiseOperationCompleted();
                if (!IsErrorHandled)
                {
                    throw error;
                }
            }
        }

        /// <summary>
        /// 结束操作。
        /// </summary>
        /// <param name="result">操作结果。</param>
        protected void Complete(object result)
        {
            EnsureNotCompleted();
            Result = result;
            IsComplete = true;
            InvokeCompleteAction();
            RaiseOperationCompleted();
        }

        /// <summary>
        /// 取消操作。
        /// </summary>
        public void Cancel()
        {
            if (CanCancel)
            {
                EnsureNotCompleted();
                IsCanceled = true;
                IsComplete = true;
                CancelCore();
                InvokeCompleteAction();
                RaiseOperationCompleted();
            }
            else
            {
                throw new NotSupportedException("The operation can not be cancel.");
            }
        }

        /// <summary>
        /// 取消操作核心方法，子类可以重写该方法。
        /// </summary>
        protected virtual void CancelCore()
        {
        }

        /// <summary>
        /// 执行结束方法。
        /// 实现类需要实现该方法，该方法会在操作执行完毕后被调用。
        /// </summary>
        protected abstract void InvokeCompleteAction();

        /// <summary>
        /// 通知操作已经结束。
        /// </summary>
        private void RaiseOperationCompleted()
        {
            if (_completed != null)
            {
                _completed(this, EventArgs.Empty);
            }
        }

        /// <summary>
        /// 触发属性变更事件。
        /// </summary>
        /// <param name="propertyName">发生变化的属性名称。</param>
        protected void RaisePropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        #endregion

        #region Events

        private EventHandler _completed;

        /// <summary>
        /// 操作执行完成事件。
        /// </summary>
        public event EventHandler Completed
        {
            add
            {
                lock (_completed)
                {
                    _completed += value;
                }
                if (this.IsComplete)
                {
                    value(this, EventArgs.Empty);
                }
            }
            remove
            {
                lock (_completed)
                {
                    _completed -= value;
                }
            }

        }

        /// <summary>
        /// 继承自<see cref="INotifyPropertyChanged"/>接口的事件。
        /// 属性变化通知事件。
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;

        #endregion
    }
}
